//
//  String.swift
//  demo
//
//  Created by ZWJY on 2021/8/20.
//

import Foundation
import UIKit
import CommonCrypto

// MARK: - 其他操作
public extension String {

    /// 字符串转Class
    var toClass: AnyClass? {
        let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String ?? ""
        guard let Class = NSClassFromString(namespace + "." + self) else {
            return nil
        }
        return Class
    }

    /// 判断字符串时候为nil, 或者 ""
    static func isNil(_ string: String?) -> Bool {
        guard let string = string, !string.isEmpty else { return true }
        return false
    }

    /// 解包后的字符串
    static func getValue(_ string: String?) -> String {
        guard  self.isNil(string) else { return string! }
        return ""
    }

    /// 字符串分割成数组
    func separatedByString(with char: String) -> Array<Any> {
        return self.components(separatedBy: char)
    }


    /// 获取子字符串的 NSRange
    func getRange(keyWord: String) -> NSRange{

        guard let range = self.range(of: keyWord) else { return NSRange(location: 0, length: 0) }

        let location = self.distance(from: self.startIndex, to: range.lowerBound)

        let length = self.distance(from: range.lowerBound, to: range.upperBound)

        return NSRange(location: location, length: length)
    }


    /// iOS16 获取子字符串的所有 [NSRange]
    func getRanges(keyWord: String) -> [NSRange]{
        guard #available(iOS 16.0, *) else {
            let range = self.getRange(keyWord: keyWord)
            return [range]
        }

        let rangs = self.ranges(of: keyWord).map({
            let location = self.distance(from: self.startIndex, to: $0.lowerBound)
            let length = self.distance(from: $0.lowerBound, to: $0.upperBound)
            return NSRange(location: location, length: length)
        })
        return rangs
    }

    /// 去除字符串中的Emoji表情
    /// - Parameter text: 字符串
    /// - Returns: 去除Emoji表情后的字符串
    func deleteEmoji() -> String {
        do {
            let regex = try NSRegularExpression(pattern: "[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]", options: NSRegularExpression.Options.caseInsensitive)

            let modifiedString = regex.stringByReplacingMatches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.count), withTemplate: "")

            return modifiedString
        } catch {
            print(error)
        }
        return ""
    }
}

// MARK: - 字符串加密，解密
public extension String {

    /// MD5 加密类型
    enum MD5EncryptType {
        /// 32 位小写
        case lowercase32
        /// 32 位大写
        case uppercase32
        /// 16 位小写
        case lowercase16
        /// 16 位大写
        case uppercase16
    }

    /// 字符串转Base64
    var base64Encode: String? {
        guard  let codingData = self.data(using: .utf8) else {
            return nil
        }
        return codingData.base64EncodedString()
    }

    /// Base64转字符串
    var base64Decode: String? {
        guard let decryptionData = Data(base64Encoded: self, options: .ignoreUnknownCharacters) else {
            return nil
        }
        return String(data: decryptionData, encoding: .utf8)
    }


    // MARK: 14.1、MD5加密 默认是32位小写加密
    /// MD5加密 默认是32位小写加密
    /// - Parameter md5Type: 加密类型
    /// - Returns: MD5加密后的字符串
    func md5Encrypt(_ md5Type: MD5EncryptType = .lowercase32) -> String {
        guard self.count > 0 else {
            print("⚠️⚠️⚠️md5加密无效的字符串⚠️⚠️⚠️")
            return ""
        }
        // 1.把待加密的字符串转成char类型数据 因为MD5加密是C语言加密
        let cCharArray = self.cString(using: .utf8)
        // 2.创建一个字符串数组接受MD5的值
        var uint8Array = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        // 3.计算MD5的值
        /*
         第一个参数:要加密的字符串
         第二个参数: 获取要加密字符串的长度
         第三个参数: 接收结果的数组
         */
        CC_MD5(cCharArray, CC_LONG(cCharArray!.count - 1), &uint8Array)

        switch md5Type {
            // 32位小写
        case .lowercase32:
            return uint8Array.reduce("") { $0 + String(format: "%02x", $1)}
            // 32位大写
        case .uppercase32:
            return uint8Array.reduce("") { $0 + String(format: "%02X", $1)}
            // 16位小写
        case .lowercase16:
            let tempStr = uint8Array.reduce("") { $0 + String(format: "%02x", $1)}
            return tempStr.slice(8..<24)
            // 16位大写
        case .uppercase16:
            let tempStr = uint8Array.reduce("") { $0 + String(format: "%02X", $1)}
            return tempStr.slice(8..<24)
        }
    }
}

// MARK: - 字符串截取操作
public extension String {

    /// 截取字符串从开始到 index
    func sub(to index: Int) -> String {
        let endIndex = validIndex(original: index)
        return String(self[self.startIndex ..< endIndex])
    }

    /// 截取字符串从index到结束
    func sub(from index: Int) -> String {
        let startIndex = validIndex(original: index)
        return String(self[startIndex ..< self.endIndex])
    }

    /// 获取指定位置和大小的字符串
    func sub(start: Int, length: Int = -1) -> String {
        var len = length
        if len == -1 {
            len = self.count - start
        }
        let st = self.index(self.startIndex, offsetBy: start)
        let en = self.index(st, offsetBy: len)
        let range = st ..< en
        return String(self[range])
    }

    /// 切割字符串(区间范围 前闭后开)  如 slice(2..<6)
    func slice(_ range: CountableRange<Int>) -> String {
        let startIndex = validIndex(original: range.lowerBound)
        let endIndex = validIndex(original: range.upperBound)
        guard startIndex < endIndex else {
            return ""
        }
        return String(self[startIndex ..< endIndex])
    }

    /// 校验字符串位置是否合理，并返回String.Index，防止越界
    /// - Parameter original: 位置
    /// - Returns: String.Index
    func validIndex(original: Int) -> String.Index {
        switch original {
        case ...self.startIndex.utf16Offset(in: self):
            return self.startIndex
        case self.endIndex.utf16Offset(in: self)...:
            return self.endIndex
        default:
            return self.index(self.startIndex, offsetBy: original)
        }
    }
}

// MARK: - 价格处理
public extension String {

    /// + (self + strNumber)
    func adding(_ strNumber: String?) -> String {

        var num1 = NSDecimalNumber.init(string: self)
        var num2 = NSDecimalNumber.init(string: strNumber)

        if num1.doubleValue.isNaN {
            num1 = NSDecimalNumber.zero
        }

        if num2.doubleValue.isNaN {
            num2 = NSDecimalNumber.zero
        }
        return num1.adding(num2).stringValue
    }

    /// - (self - strNumber)
    func subtracting(_ strNumber: String?) -> String {

        var num1 = NSDecimalNumber.init(string: self)
        var num2 = NSDecimalNumber.init(string: strNumber)

        if num1.doubleValue.isNaN {
            num1 = NSDecimalNumber.zero
        }

        if num2.doubleValue.isNaN {
            num2 = NSDecimalNumber.zero
        }
        return num1.subtracting(num2).stringValue
    }

    /// * (self * strNumber)
    func multiplying(_ strNumber: String?) -> String {

        var num1 = NSDecimalNumber.init(string: self)
        var num2 = NSDecimalNumber.init(string: strNumber)

        if num1.doubleValue.isNaN {
            num1 = NSDecimalNumber.zero
        }

        if num2.doubleValue.isNaN {
            num2 = NSDecimalNumber.zero
        }
        return num1.multiplying(by: num2).stringValue
    }

    /// ÷ (self / strNumber)
    func dividing(_ strNumber: String?) -> String {

        var num1 = NSDecimalNumber.init(string: self)
        var num2 = NSDecimalNumber.init(string: strNumber)

        if num1.doubleValue.isNaN {
            num1 = NSDecimalNumber.zero
        }

        if num2.doubleValue.isNaN {
            num2 = NSDecimalNumber.one
        }

        if num2.doubleValue == 0 {
            num2 = NSDecimalNumber.one
        }

        return num1.dividing(by: num2).stringValue
    }

    /// 精确计算结果处理
    /// - Parameters:
    ///   - value: 需处理数据
    ///   - model: 结果处理方式，plan 四舍五入，dowm只舍不入，up只入不舍，banker 特殊要求的四舍五入
    ///   - scale: 精确到几位小数
    ///   - raiseOnExactness: 发生精确错误时是否抛出异常，一般为NO
    ///   - raiseOnOverflow: 发生溢出错误时是否抛出异常，一般为NO
    ///   - raiseOnUnderflow: 发生不足错误时是否抛出异常，一般为NO
    ///   - raiseOnDivideByZero: 被0除时是否抛出异常，一般为YES
    /// - Returns: 转换为字符串返回
    func setupValue(_ value: NSDecimalNumber, _ model: NSDecimalNumber.RoundingMode = .plain, _ scale: Int16 = 2, _ raiseOnExactness: Bool = false, _ raiseOnOverflow: Bool = false, _ raiseOnUnderflow: Bool = false,  _ raiseOnDivideByZero: Bool = true) -> String {

        let handler = NSDecimalNumberHandler.init(roundingMode: model, scale: scale, raiseOnExactness: raiseOnExactness, raiseOnOverflow: raiseOnOverflow, raiseOnUnderflow: raiseOnUnderflow, raiseOnDivideByZero: raiseOnDivideByZero)

        let number = value.rounding(accordingToBehavior: handler)

        return number.stringValue
    }

    /// 将金额字符串转化为带逗号的金额 按照千分位划分，如  "1234567" => 1,234,567   1234567.56 => 1,234,567.56
    func toThousands() -> String? {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.roundingMode = .floor
        formatter.maximumFractionDigits = 0
        formatter.minimumFractionDigits = 0
        if self.contains(".") {
            formatter.maximumFractionDigits = 2
            formatter.minimumFractionDigits = 2
            formatter.minimumIntegerDigits = 1
        }
        var num = NSDecimalNumber(string: self)
        if num.doubleValue.isNaN {
            num = NSDecimalNumber(string: "0")
        }
        let result = formatter.string(from: num)
        return result
    }
}

//字符串宽高处理
public extension String {
    
    /// 获取字符串的宽度
    /// - Parameters:
    ///   - font: 字体
    ///   - maxHeight: 最大高度
    /// - Returns: 字符串宽度
    func width(ofFont font: UIFont, maxWidth: CGFloat = CGFloat(MAXFLOAT), maxHeight: CGFloat) -> CGFloat {
        getSize(ofAttributes: [.font: font], maxWidth: maxWidth, maxHeight: maxHeight).width
    }
    
    /// 获取字符串的高度
    /// - Parameters:
    ///   - font: 字体
    ///   - maxWidth: 最大宽度
    /// - Returns: 字符串高度
    func height(ofFont font: UIFont, maxWidth: CGFloat) -> CGFloat {
        getSize(ofAttributes: [.font: font], maxWidth: maxWidth, maxHeight: CGFloat(MAXFLOAT)).height
    }
    
    fileprivate func getSize(ofAttributes attributes: [NSAttributedString.Key: Any], maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
        let constraintRect = CGSize(width: maxWidth, height: maxHeight)
        let ocString = self as NSString
        let boundingBox = ocString.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: attributes, context:  nil)
        return boundingBox.size
    }
}
